package com.zhu.rtda.heap.constant;

import com.zhu.classfile.constant.ConstantInfo;
import com.zhu.classfile.constant.base.ConstantInterfaceMethodrefInfo;
import com.zhu.rtda.heap.InstanceKlass;
import com.zhu.rtda.heap.Method;

/**
 * 接口方法符号引用
 *
 * 对应 Go 的：
 *
 * type InterfaceMethodRef struct {
 *     MemberRef
 *     method *Method
 * }
 */
public class InterfaceMethodRef extends MemberRef {

    // 指向解析后的接口方法
    private Method method;

    // region 构造与工厂方法

    /**
     * 私有构造，禁止直接实例化
     */
    private InterfaceMethodRef() {}

    /**
     * 工厂方法：从 class 文件的 ConstantInterfaceMethodrefInfo 创建接口方法引用
     *
     * 对应 Go 的 newInterfaceMethodRef(cp *ConstantPool, refInfo *ConstantInterfaceMethodrefInfo)
     *
     * @param cp 运行时常量池
     * @param interfaceMethodrefInfo class 文件中的 ConstantInterfaceMethodrefInfo
     * @return 接口方法引用
     */
    public static InterfaceMethodRef newInterfaceMethodRef(RuntimeConstantPool cp, ConstantInterfaceMethodrefInfo interfaceMethodrefInfo) {

        InterfaceMethodRef ref = new InterfaceMethodRef();
        ref.runtimeConstantPool=cp;
        // 强制转换并复制类、名称、描述符
        ref.copyMemberRefInfo(interfaceMethodrefInfo);
        return ref;
    }

    // endregion

    // region 核心方法

    /**
     * 获取解析后的接口方法
     *
     * 对应 Go 的 ResolvedInterfaceMethod()
     *
     * 如果尚未解析，则触发解析
     */
    public Method resolvedInterfaceMethod() {
        if (this.method == null) {
            resolveInterfaceMethodRef();
        }
        return this.method;
    }

    /**
     * 解析接口方法引用
     * 对应 Go 的 resolveInterfaceMethodRef()
     *
     * jvms8 5.4.3.4
     */
    private void resolveInterfaceMethodRef() {
        // 1. 获取当前使用该符号引用的类（用于访问控制，但接口方法通常无需严格检查）
        InstanceKlass d = this.runtimeConstantPool.getInstanceKlass();

        // 2. 解析接口（classIndex -> InstanceKlass）
        InstanceKlass iface = this.resolvedKlass();

        // 3. 检查：iface 必须是接口（否则 IncompatibleClassChangeError）
        if (!iface.isInterface()) {
            throw new IncompatibleClassChangeError();
        }

        // 4. 在 iface 及其父接口中查找方法
        Method method = lookupMethodInInterfaces(iface, this.name, this.descriptor);
        if (method == null) {
            throw new NoSuchMethodError(this.name + this.descriptor);
        }

        // 5. 接口方法默认是 public，通常可访问，但为安全仍做检查
        if (!method.isAccessibleTo(d)) {
            throw new IllegalAccessError();
        }

        this.method = method;
    }

    /**
     * 在接口及其父接口中递归查找方法
     */
    private static Method lookupMethodInInterfaces(InstanceKlass iface, String name, String descriptor) {
        // 先查当前接口
        for (Method method : iface.getMethods()) {
            if (method.getName().equals(name) && method.getDescriptor().equals(descriptor)) {
                return method;
            }
        }

        // 再查父接口
        for (InstanceKlass superIface : iface.getInterfaces()) {
            Method method = lookupMethodInInterfaces(superIface, name, descriptor);
            if (method != null) {
                return method;
            }
        }

        return null;
    }



    public Method getMethod() {
        return method;
    }


}